home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / mops / tinyexam.scm < prev   
Text File  |  1993-07-23  |  10KB  |  362 lines

  1. ; Mode: Scheme
  2. ;
  3. ;
  4. ; **********************************************************************
  5. ; Copyright (c) 1992 Xerox Corporation.  
  6. ; All Rights Reserved.  
  7. ;
  8. ; Use, reproduction, and preparation of derivative works are permitted.
  9. ; Any copy of this software or of any derivative work must include the
  10. ; above copyright notice of Xerox Corporation, this paragraph and the
  11. ; one after it.  Any distribution of this software or derivative works
  12. ; must comply with all applicable United States export control laws.
  13. ;
  14. ; This software is made available AS IS, and XEROX CORPORATION DISCLAIMS
  15. ; ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE
  16. ; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  17. ; PURPOSE, AND NOTWITHSTANDING ANY OTHER PROVISION CONTAINED HEREIN, ANY
  18. ; LIABILITY FOR DAMAGES RESULTING FROM THE SOFTWARE OR ITS USE IS
  19. ; EXPRESSLY DISCLAIMED, WHETHER ARISING IN CONTRACT, TORT (INCLUDING
  20. ; NEGLIGENCE) OR STRICT LIABILITY, EVEN IF XEROX CORPORATION IS ADVISED
  21. ; OF THE POSSIBILITY OF SUCH DAMAGES.
  22. ; **********************************************************************
  23. ;
  24. ; Some simple examples of using Tiny CLOS and its MOP.
  25. ; Much of this stuff corresponds to stuff in AMOP (The Art of the
  26. ; Metaobject Protocol).
  27. ;
  28.  
  29. ;***
  30. ;
  31. ; This is a useful sort of helper function.  Note how it uses the
  32. ; introspective part of the MOP.  The first few pages of chapter
  33. ; two of the AMOP discuss this.
  34. ;
  35. ; Note that this introspective MOP doesn't support back-links from
  36. ; the classes to methods and generic functions.  Is that worth adding?
  37. ;
  38. ;
  39. (define initialize-slots
  40.     (lambda (object initargs)
  41.       (let ((not-there (list 'shes-not-there)))
  42.     (for-each (lambda (slot)
  43.             (let ((name (car slot)))
  44.               (let ((value  (getl initargs name not-there)))
  45.             (if (eq? value not-there)
  46.                 'do-nothing
  47.                 (slot-set! object name value)))))
  48.           (class-slots (class-of object))))))
  49.  
  50.  
  51.  
  52. ;***
  53. ;
  54. ; A simple class, just an instance of <class>.  Note that we are using
  55. ; make and <class> rather than make-class to make it.  See Section 2.4
  56. ; of AMOP for more on this.
  57. ;
  58. ;
  59.  
  60. (define <pos> (make <class>                          ;[make-class 
  61.             'direct-supers (list <object>)   ;  (list <object>) 
  62.             'direct-slots  (list 'x 'y)))    ;  (list 'x 'y)]
  63.  
  64. (add-method initialize
  65.     (make-method (list <pos>)
  66.       (lambda (call-next-method pos initargs)
  67.     (call-next-method)
  68.     (initialize-slots pos initargs))))
  69.  
  70. (define p1 (make <pos> 'x 1 'y 2))
  71. (define p2 (make <pos> 'x 3 'y 5))
  72.  
  73.  
  74. ;***
  75. ;
  76. ; Another way of writing that class definition, that achives better
  77. ; `encapsulation' by using slot names that are unique keys, rather
  78. ; than symbols.
  79. ;
  80. ;
  81.  
  82. (define <pos>)
  83. (define pos-x (make-generic))
  84. (define pos-y (make-generic))
  85. (define move  (make-generic))
  86.  
  87. (let ((x (vector 'x))
  88.       (y (vector 'y)))
  89.   
  90.   (set! <pos> (make <class>
  91.             'direct-supers (list <object>)
  92.             'direct-slots  (list x y)))
  93.  
  94.   (add-method pos-x
  95.       (make-method (list <pos>)
  96.     (lambda (call-next-method pos) (slot-ref pos x))))
  97.   (add-method pos-y
  98.       (make-method (list <pos>)
  99.     (lambda (call-next-method pos) (slot-ref pos y))))
  100.  
  101.   (add-method move
  102.       (make-method (list <pos>)
  103.         (lambda (call-next-method pos new-x new-y)
  104.       (slot-set! pos x new-x)
  105.       (slot-set! pos y new-y))))
  106.  
  107.   (add-method initialize
  108.       (make-method (list <pos>)
  109.     (lambda (call-next-method pos initargs)
  110.       (move pos (getl initargs 'x 0) (getl initargs 'y 0)))))
  111.   )
  112.  
  113.  
  114. (define p3 (make <pos> 'x 1 'y 2))
  115. (define p4 (make <pos> 'x 3 'y 5))
  116.  
  117.  
  118. ;***
  119. ;
  120. ; Class allocated slots.
  121. ;
  122. ; In Scheme, this extension isn't worth a whole lot, but what the hell.
  123. ;
  124. ;
  125.  
  126. (define <class-slots-class>
  127.     (make-class (list <class>)
  128.         (list)))
  129.  
  130. (add-method compute-getter-and-setter
  131.     (make-method (list <class-slots-class>)
  132.       (lambda (call-next-method class slot allocator)
  133.     (if (null? (memq ':class-allocation slot))
  134.         (call-next-method)
  135.         (let ((cell '()))
  136.           (list (lambda (o) cell)
  137.             (lambda (o new) (set! cell new) new)))))))
  138.  
  139.  
  140. ;
  141. ; Here's a silly program that uses class allocated slots.
  142. ;
  143. ;
  144. (define <ship>
  145.     (make <class-slots-class>
  146.       'direct-supers (list <object>)
  147.       'direct-slots  (list 'name
  148.                    '(all-ships :class-allocation))))
  149.  
  150. (add-method initialize
  151.     (make-method (list <ship>)
  152.       (lambda (call-next-method ship initargs)
  153.     (call-next-method)
  154.     (initialize-slots ship initargs)
  155.     (slot-set! ship
  156.            'all-ships
  157.            (cons ship (slot-ref ship 'all-ships))))))
  158.  
  159. (define siblings (make-generic))
  160. (add-method siblings
  161.     (make-method (list <ship>)
  162.       (lambda (call-next-method ship)
  163.     (remove ship (slot-ref ship 'all-ships)))))
  164.  
  165. (define s1 (make <ship> 'name 's1))
  166. (define s2 (make <ship> 'name 's2))
  167. (define s3 (make <ship> 'name 's3))
  168.  
  169.  
  170.  
  171. ;***
  172. ;
  173. ; Here's a class of class that allocates some slots dynamically.
  174. ;
  175. ; It has a layered protocol (dynamic-slot?) that decides whether a given
  176. ; slot should be dynamically allocated.  This makes it easy to define a
  177. ; subclass that allocates all its slots dynamically.
  178. ;
  179. ;
  180. (define <dynamic-class>
  181.     (make-class (list <class>)
  182.         (list 'alist-g-n-s)))
  183.  
  184.  
  185. (define dynamic-slot? (make-generic))
  186.  
  187. (add-method dynamic-slot?
  188.     (make-method (list <dynamic-class>)
  189.       (lambda (call-next-method class slot)
  190.     (memq :dynamic-allocation (cdr slot)))))
  191.  
  192.  
  193.  
  194. (define alist-getter-and-setter
  195.     (lambda (dynamic-class allocator)
  196.       (let ((old (slot-ref dynamic-class 'alist-g-n-s)))
  197.     (if (null? old)
  198.         (let ((new (allocator (lambda () '()))))
  199.           (slot-set! dynamic-class 'alist-g-n-s new)
  200.           new)
  201.         old))))
  202.  
  203.  
  204. (add-method compute-getter-and-setter
  205.     (make-method (list <dynamic-class>)
  206.       (lambda (call-next-method class slot allocator)
  207.     (if (null? (dynamic-slot? class slot))
  208.         (call-next-method)
  209.         (let* ((name (car slot))
  210.            (g-n-s (alist-getter-and-setter class allocator))
  211.            (alist-getter (car g-n-s))
  212.            (alist-setter (cadr g-n-s)))
  213.           (list (lambda (o)
  214.               (let ((entry (assq name  (alist-getter o))))
  215.             (if (null? entry)
  216.                 '()
  217.                 (cdr entry))))
  218.             (lambda (o new)
  219.               (let* ((alist (alist-getter o))
  220.                  (entry (assq name alist)))
  221.             (if (null? entry)
  222.                 (alist-setter o
  223.                               (cons (cons name new) alist))
  224.                 (set-cdr! entry new))
  225.             new))))))))
  226.  
  227.  
  228. (define <all-dynamic-class>
  229.     (make-class (list <dynamic-class>)
  230.         (list)))
  231.  
  232. (add-method dynamic-slot?
  233.     (make-method (list <all-dynamic-class>)
  234.       (lambda (call-next-method class slot) #t)))
  235.         
  236.  
  237.  
  238. ;
  239. ; A silly program that uses this.
  240. ;
  241. ;
  242. (define <person> (make <all-dynamic-class>
  243.                'direct-supers (list <object>)
  244.                'direct-slots  (list 'name 'age 'address)))
  245.  
  246. (add-method initialize
  247.     (make-method (list <person>)
  248.       (lambda (call-next-method person initargs)
  249.     (initialize-slots person initargs))))
  250.  
  251.  
  252. (define person1 (make <person> 'name 'sally))
  253. (define person2 (make <person> 'name 'betty))
  254. (define person3 (make <person> 'name 'sue))
  255.  
  256.  
  257. ;***
  258. ;
  259. ; A ``database'' class that stores slots externally.
  260. ;
  261. ;
  262.  
  263. (define <db-class>
  264.   (make-class (list <class>)
  265.           (list 'id-g-n-s)))
  266.  
  267. (define id-getter-and-setter
  268.     (lambda (db-class allocator)
  269.       (let ((old (slot-ref db-class 'id-g-n-s)))
  270.     (if (null? old)
  271.         (let ((new (allocator db-allocate-id)))
  272.           (slot-set! class 'id-g-n-s new)
  273.           new)
  274.         old))))
  275.  
  276. (add-method compute-getter-and-setter
  277.     (make-method (list <db-class>)
  278.       (lambda (call-next-method class slot allocator)
  279.     (let* ((id-g-n-s (id-getter-and-setter class allocator))
  280.            (id-getter (car id-g-n-s))
  281.            (id-setter (cadr id-g-n-s))
  282.            (slot-name (car slot)))
  283.       (list (lambda (o)
  284.           (db-lookup (id-getter o) slot-name)) 
  285.         (lambda (o new)
  286.           (db-store  (id-getter o) slot-name new)))))))
  287.  
  288.  
  289. ;***
  290. ;
  291. ; A kind of generic that supports around methods.
  292. ;
  293. ;
  294. (define make-around-generic
  295.     (lambda () (make <around-generic>)))
  296.  
  297. (define make-around-method
  298.     (lambda (specializers procedure)
  299.       (make <around-method>
  300.         'specializers specializers
  301.         'procedure procedure)))
  302.  
  303.  
  304. (define <around-generic> (make <entity-class>
  305.                    'direct-supers (list <generic>)))
  306. (define <around-method>  (make <class>
  307.                    'direct-supers (list <method>)))
  308.  
  309.  
  310. (define around-method?   (make-generic))
  311.  
  312. (add-method around-method?
  313.     (make-method (list <method>)
  314.       (lambda (call-next-method x) #f)))
  315. (add-method around-method?
  316.     (make-method (list <around-method>)
  317.       (lambda (call-next-method x) #t)))
  318.  
  319.  
  320. (add-method compute-methods
  321.     (make-method (list <around-generic>)
  322.       (lambda (call-next-method generic)
  323.     (let ((normal-compute-methods (call-next-method)))
  324.       (lambda (args)
  325.         (let ((normal-methods (normal-compute-methods args)))
  326.           (append
  327.             (filter-in around-method?
  328.                normal-methods)
  329.         (filter-in (lambda (m) (not (around-method? m)))
  330.                normal-methods))))))))
  331.  
  332.  
  333. ;
  334. ; And a simple example of using it.
  335. ;
  336. ;
  337. (define <baz> (make-class (list <object>) (list)))
  338. (define <bar> (make-class (list <baz>)    (list)))
  339. (define <foo> (make-class (list <bar>)    (list)))
  340.  
  341.  
  342. (define test-around
  343.     (lambda (generic)
  344.       (add-method generic
  345.       (make-method        (list <foo>)
  346.                           (lambda (cnm x) (cons 'foo (cnm)))))
  347.  
  348.       (add-method generic
  349.       (make-around-method (list <bar>)
  350.                   (lambda (cnm x) (cons 'bar (cnm)))))
  351.  
  352.       (add-method generic
  353.       (make-method        (list <baz>)
  354.                           (lambda (cnm x) '(baz))))
  355.  
  356.       (generic (make <foo>))))
  357.  
  358.  
  359. (equal? (test-around (make-generic))        '(foo bar baz))
  360. (equal? (test-around (make-around-generic)) '(bar foo baz))
  361.